package com.bxs.detector.impl;

import com.bxs.detector.BaseDetector;
import com.bxs.pojo.BaseRule;
import com.bxs.pojo.DangerMsg;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.pcap4j.core.PcapPacket;
import org.pcap4j.packet.IcmpV4CommonPacket;
import org.pcap4j.packet.IpPacket;
import org.pcap4j.packet.TcpPacket;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;

// TCP数据报检测(网际层数据报检测)
@Component
public class TcpPacketDetector extends BaseDetector {
    @Override
    public DangerMsg detect(PcapPacket packet, List<BaseRule> rules) throws UnsupportedEncodingException, JsonProcessingException {
        // 解析为ICMP数据报
        TcpPacket pack = packet.get(TcpPacket.class);
        if(pack == null)return null;
        System.out.println("检测到tcp报文");
        // 字段检测
        ObjectMapper objectMapper = new ObjectMapper();
//        System.out.println("start IpPacketDetector" + rules);
        // 规则数量较少则直接检测
        for(BaseRule rule : rules){
            String protocolType = rule.getProtocolType();
            if (!protocolType.equals("TCP"))continue;                                     // 不是ICMP报文的规则交给其他的处理
            // 获取规则中的字段匹配值
            String protocolFields = rule.getProtocolFields() == null ? "{}" : rule.getProtocolFields();
            Map<String, String> map = objectMapper.readValue(protocolFields, Map.class);
            boolean pass = true;
            // tcp协议首部字段(实际上tcp首部中一般只根据端口号进行过滤)
            if(rule.getSourcePort() != -1 && pack.getHeader().getSrcPort().valueAsInt() != rule.getSourcePort()){
                continue;
            }
            if(rule.getTargetPort() != -1 && pack.getHeader().getDstPort().valueAsInt() != rule.getTargetPort()){
                continue;
            }

            // 报文首部字段检测(URG,ACK,PSH,RST,SYN,FIN)
            boolean danger = false;
            if(map.containsKey("URG") && pack.getHeader().getUrg() && Integer.valueOf(map.get("URG")) == 1){
                danger = true;
            }else if(map.containsKey("ACK") && pack.getHeader().getAck() && Integer.valueOf(map.get("ACK")) == 1){
                danger = true;
            }else if(map.containsKey("PSH") && pack.getHeader().getPsh() && Integer.valueOf(map.get("PSH")) == 1){
                danger = true;
            }else if(map.containsKey("RST") && pack.getHeader().getRst() && Integer.valueOf(map.get("RST")) == 1){
                danger = true;
            }else if(map.containsKey("SYN") && pack.getHeader().getUrg() && Integer.valueOf(map.get("SYN")) == 1){
                danger = true;
            }else if(map.containsKey("FIN") && pack.getHeader().getFin() && Integer.valueOf(map.get("FIN")) == 1){
                danger = true;
            }
            if(danger){
                System.out.println("报文首部检测到危险");
                DangerMsg dangerMsg = new DangerMsg();
                dangerMsg.setPacket(packet);
                dangerMsg.setCode(rule.getLevel());
                IpPacket ipPacket = packet.get(IpPacket.class);
                dangerMsg.setSourceIp(ipPacket.getHeader().getSrcAddr().getHostName());
                dangerMsg.setTargetIp(ipPacket.getHeader().getDstAddr().getHostName());
                dangerMsg.setTargetPort(pack.getHeader().getDstPort().valueAsInt());
                dangerMsg.setSourcePort(pack.getHeader().getSrcPort().valueAsInt());
                dangerMsg.setDate(new Date());
                dangerMsg.setDesc(rule.getMsg());
                return dangerMsg;
            }
            System.out.println("detect content: " + rule.text.trim());
            // 检查主体数据
            if (!rule.text.trim().equals("")){
                byte[] rawData = pack.getRawData();
                // 解码
                String packetData = new String(rawData, "UTF-8");
                if (packetData.indexOf(rule.getText()) != -1){
                    // 所有条件均符合
                    DangerMsg dangerMsg = new DangerMsg();
                    dangerMsg.setPacket(packet);
                    dangerMsg.setCode(rule.getLevel());
                    IpPacket ipPacket = packet.get(IpPacket.class);
                    dangerMsg.setSourceIp(ipPacket.getHeader().getSrcAddr().getHostName());
                    dangerMsg.setTargetIp(ipPacket.getHeader().getDstAddr().getHostName());
                    dangerMsg.setTargetPort(pack.getHeader().getDstPort().valueAsInt());
                    dangerMsg.setSourcePort(pack.getHeader().getSrcPort().valueAsInt());
                    dangerMsg.setDate(new Date());
                    dangerMsg.setDesc(rule.getMsg());
                    return dangerMsg;
                }
            }
        }
        return null;
    }
}
